/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package signandverify;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.Signature;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.logging.Level;
import java.util.logging.Logger;
// http://www.bouncycastle.org/latest_releases.html
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMWriter;
/**
 *
 * @author rmartinezch
 */
public class SignAndVerify {

    /**
     * @param args the command line arguments
     */
    static PrivateKey privateKey = null;
    static Certificate certificate = null;
    static byte[] signatureValue = null;
    static String msg = "Hello world !!!";
    static String alg = "SHA256withRSA";// "SHA1withRSA";
    static String hash = "SHA-256";// "SHA1";

    public static void main(String[] args) throws KeyStoreException, NoSuchProviderException, FileNotFoundException, IOException, CertificateException, NoSuchAlgorithmException, UnrecoverableKeyException, InvalidKeyException, SignatureException {
        // TODO code application logic here
        Security.addProvider(new BouncyCastleProvider());
        KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
        ks.load(new FileInputStream("mpaula3.p12"), "mpaula3".toCharArray());

        Enumeration<String> aliases = ks.aliases();
        while (aliases.hasMoreElements()) {
            String alias = aliases.nextElement();
            System.out.println("alias : " + alias);
//            /*  first key
            if (ks.isKeyEntry(alias)) {
                privateKey = (PrivateKey) ks.getKey(alias, null);
                certificate = ks.getCertificate(alias);
                break;
            }
//            */
        }

        try {
            
            OutputStreamWriter output = new OutputStreamWriter(System.out);
        PEMWriter pem = new PEMWriter(output);
        pem.writeObject(certificate);
        pem.close();
            
            sign();
//            verify();
        } catch (KeyStoreException ex) {
            Logger.getLogger(SignAndVerify.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(SignAndVerify.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(SignAndVerify.class.getName()).log(Level.SEVERE, null, ex);
        } catch (CertificateException ex) {
            Logger.getLogger(SignAndVerify.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnrecoverableKeyException ex) {
            Logger.getLogger(SignAndVerify.class.getName()).log(Level.SEVERE, null, ex);
        } catch (InvalidKeyException ex) {
            Logger.getLogger(SignAndVerify.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SignatureException ex) {
            Logger.getLogger(SignAndVerify.class.getName()).log(Level.SEVERE, null, ex);
        } catch (NoSuchProviderException ex) {
            Logger.getLogger(SignAndVerify.class.getName()).log(Level.SEVERE, null, ex);
        }

        System.out.println("Hello world ...");
    }

    static public void sign() throws NoSuchProviderException, UnrecoverableKeyException, CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
//        String msg = "Hello world !!!";
        System.out.println("hex message : " + byteArrayToHex(msg.getBytes()));
        
        MessageDigest mDigest = MessageDigest.getInstance(hash);
        byte[] result = mDigest.digest(msg.getBytes());
        System.out.println("hex hash : " + result.length + " - " + byteArrayToHex(result));

        Signature sig = Signature.getInstance(alg);
        sig.initSign(privateKey);
        sig.update(msg.getBytes());

        signatureValue = sig.sign();
        System.out.println("hex sign : " + signatureValue.length + " - " + byteArrayToHex(signatureValue));
    }

    static public void verify() throws NoSuchProviderException, UnrecoverableKeyException, CertificateException, IOException, KeyStoreException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
        Signature sig = Signature.getInstance(alg);
        sig.initVerify(certificate.getPublicKey());
        sig.update(msg.getBytes());

        boolean valid = sig.verify(signatureValue); // signatureValue let it by sign() function
        System.out.println("r : " + valid);
    }

    static public String byteArrayToHex(byte[] a) {
        StringBuilder sb = new StringBuilder();
        for (byte b : a) {
            sb.append(String.format("%02x", b & 0xff));
        }
        return sb.toString().toUpperCase();
    }

    static public X509Certificate getCertificate(InputStream cert) {
        X509Certificate tlCert = null;
        CertificateFactory factory = null;
        try {
            factory = CertificateFactory.getInstance("X509");
        } catch (CertificateException e) {
            System.out.println("Certificado X509 no soportado" + e.getLocalizedMessage());
            return null;
        }

        try {
            tlCert = (X509Certificate) factory.generateCertificate(cert);
        } catch (Exception e) {
            System.out.println("Loading certificate exception" + e.getLocalizedMessage());
        }
        return tlCert;
    }
    
}
